package com.icongyou.enterprise.talent_analysis.controller;

import com.icongyou.enterprise.talent_analysis.entity.*;
import com.icongyou.enterprise.talent_analysis.service.AIInsightCacheService;
import com.icongyou.enterprise.talent_analysis.service.AIInsightService;
import com.icongyou.enterprise.talent_analysis.service.HrTemplatePreferenceService;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import java.time.LocalDateTime;
import java.util.*;

import static org.mockito.ArgumentMatchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.hamcrest.Matchers.*;

/**
 * AI洞察控制器测试
 * 测试REST API端点、参数验证、缓存策略、异常处理
 */
@SpringBootTest
@AutoConfigureMockMvc
public class AIInsightControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private AIInsightService aiInsightService;

    @MockBean
    private AIInsightCacheService cacheService;

    @MockBean
    private HrTemplatePreferenceService preferenceService;

    @Test
    public void testGetStudentInsight_withCacheHit() throws Exception {
        String studentId = "660e8400-e29b-41d4-a716-446655440101";
        String templateId = "template123";

        StudentInsight cachedInsight = createMockInsight(studentId);
        
        Mockito.when(preferenceService.getCurrentTemplateId("hr001"))
            .thenReturn(templateId);
        Mockito.when(cacheService.getFromCache(studentId, templateId))
            .thenReturn(cachedInsight);

        mockMvc.perform(get("/api/talent-analysis/ai-insight/student/{studentId}", studentId)
                .param("hrUserId", "hr001"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data.studentId").value(studentId))
            .andExpect(jsonPath("$.data.studentName").value("张三"))
            .andExpect(jsonPath("$.data.major").value("软件工程"));

        // 验证缓存命中后不调用Service生成
        Mockito.verify(aiInsightService, Mockito.never()).generateStudentInsight(anyString(), anyString());
    }

    @Test
    public void testGetStudentInsight_withCacheMiss() throws Exception {
        String studentId = "660e8400-e29b-41d4-a716-446655440101";
        String templateId = "template123";

        StudentInsight generatedInsight = createMockInsight(studentId);
        
        Mockito.when(preferenceService.getCurrentTemplateId("hr001"))
            .thenReturn(templateId);
        Mockito.when(cacheService.getFromCache(studentId, templateId))
            .thenReturn(null); // 缓存未命中
        Mockito.when(aiInsightService.generateStudentInsight(studentId, "hr001"))
            .thenReturn(generatedInsight);

        mockMvc.perform(get("/api/talent-analysis/ai-insight/student/{studentId}", studentId)
                .param("hrUserId", "hr001"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data.studentId").value(studentId));

        // 验证实时生成并更新缓存
        Mockito.verify(aiInsightService).generateStudentInsight(studentId, "hr001");
        Mockito.verify(cacheService).putToCache(studentId, templateId, generatedInsight);
    }

    @Test
    public void testGetStudentInsight_withoutHrUser() throws Exception {
        String studentId = "660e8400-e29b-41d4-a716-446655440101";

        StudentInsight generatedInsight = createMockInsight(studentId);
        
        Mockito.when(cacheService.getFromCache(studentId, null))
            .thenReturn(null);
        Mockito.when(aiInsightService.generateStudentInsight(studentId, null))
            .thenReturn(generatedInsight);

        mockMvc.perform(get("/api/talent-analysis/ai-insight/student/{studentId}", studentId))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data.studentId").value(studentId));

        // 验证使用默认模板
        Mockito.verify(preferenceService, Mockito.never()).getCurrentTemplateId(anyString());
        Mockito.verify(aiInsightService).generateStudentInsight(studentId, null);
    }

    @Test
    public void testGetStudentInsight_serviceException() throws Exception {
        String studentId = "660e8400-e29b-41d4-a716-446655440101";

        Mockito.when(cacheService.getFromCache(anyString(), any()))
            .thenReturn(null);
        Mockito.when(aiInsightService.generateStudentInsight(anyString(), any()))
            .thenThrow(new RuntimeException("AI服务不可用"));

        mockMvc.perform(get("/api/talent-analysis/ai-insight/student/{studentId}", studentId))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(500))
            .andExpect(jsonPath("$.message", containsString("生成AI洞察失败")));
    }

    @Test
    public void testGetJobRecommendations_success() throws Exception {
        String studentId = "660e8400-e29b-41d4-a716-446655440101";

        List<JobRecommendation> recommendations = Arrays.asList(
            createMockJobRecommendation("软件开发工程师", 95.0),
            createMockJobRecommendation("产品经理", 85.0),
            createMockJobRecommendation("项目经理", 80.0)
        );

        Mockito.when(aiInsightService.recommendJobs(studentId, 3, "hr001"))
            .thenReturn(recommendations);

        mockMvc.perform(get("/api/talent-analysis/ai-insight/student/{studentId}/jobs", studentId)
                .param("topN", "3")
                .param("hrUserId", "hr001"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data", hasSize(3)))
            .andExpect(jsonPath("$.data[0].jobTitle").value("软件开发工程师"))
            .andExpect(jsonPath("$.data[0].matchScore").value(95.0));
    }

    @Test
    public void testGetJobRecommendations_defaultTopN() throws Exception {
        String studentId = "660e8400-e29b-41d4-a716-446655440101";

        List<JobRecommendation> recommendations = Arrays.asList(
            createMockJobRecommendation("软件开发工程师", 95.0),
            createMockJobRecommendation("产品经理", 85.0),
            createMockJobRecommendation("项目经理", 80.0)
        );

        Mockito.when(aiInsightService.recommendJobs(studentId, 3, null))
            .thenReturn(recommendations);

        mockMvc.perform(get("/api/talent-analysis/ai-insight/student/{studentId}/jobs", studentId))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data", hasSize(3)));
    }

    @Test
    public void testGetJobRecommendations_invalidTopN_tooSmall() throws Exception {
        String studentId = "660e8400-e29b-41d4-a716-446655440101";

        mockMvc.perform(get("/api/talent-analysis/ai-insight/student/{studentId}/jobs", studentId)
                .param("topN", "0"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(500))
            .andExpect(jsonPath("$.message", containsString("推荐数量必须在1-5之间")));
    }

    @Test
    public void testGetJobRecommendations_invalidTopN_tooLarge() throws Exception {
        String studentId = "660e8400-e29b-41d4-a716-446655440101";

        mockMvc.perform(get("/api/talent-analysis/ai-insight/student/{studentId}/jobs", studentId)
                .param("topN", "10"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(500))
            .andExpect(jsonPath("$.message", containsString("推荐数量必须在1-5之间")));
    }

    @Test
    public void testAnalyzeStrengthsWeaknesses_success() throws Exception {
        String studentId = "660e8400-e29b-41d4-a716-446655440101";

        Map<String, List<String>> result = new HashMap<>();
        result.put("strengths", Arrays.asList("技术能力强", "学习能力优秀", "团队协作好"));
        result.put("weaknesses", Arrays.asList("沟通能力需提升", "时间管理有待加强"));

        Mockito.when(aiInsightService.analyzeStrengthsAndWeaknesses(studentId, "hr001"))
            .thenReturn(result);

        mockMvc.perform(get("/api/talent-analysis/ai-insight/student/{studentId}/strengths-weaknesses", studentId)
                .param("hrUserId", "hr001"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data.strengths", hasSize(3)))
            .andExpect(jsonPath("$.data.weaknesses", hasSize(2)))
            .andExpect(jsonPath("$.data.strengths[0]").value("技术能力强"));
    }

    @Test
    public void testAnalyzeStrengthsWeaknesses_withoutHrUser() throws Exception {
        String studentId = "660e8400-e29b-41d4-a716-446655440101";

        Map<String, List<String>> result = new HashMap<>();
        result.put("strengths", Arrays.asList("综合能力优秀"));
        result.put("weaknesses", Arrays.asList("需要继续努力"));

        Mockito.when(aiInsightService.analyzeStrengthsAndWeaknesses(studentId, null))
            .thenReturn(result);

        mockMvc.perform(get("/api/talent-analysis/ai-insight/student/{studentId}/strengths-weaknesses", studentId))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200));
    }

    @Test
    public void testGetTaskCategoryAnalysis_success() throws Exception {
        String studentId = "660e8400-e29b-41d4-a716-446655440101";

        TaskCategoryAnalysis analysis = createMockTaskAnalysis();

        Mockito.when(aiInsightService.analyzeTaskCategoryPerformance(studentId))
            .thenReturn(analysis);

        mockMvc.perform(get("/api/talent-analysis/ai-insight/student/{studentId}/task-performance", studentId))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data.performanceTrend").value("进步明显"))
            .andExpect(jsonPath("$.data.aiSummary", notNullValue()));
    }

    @Test
    public void testGetCareerAdvice_success() throws Exception {
        String studentId = "660e8400-e29b-41d4-a716-446655440101";
        String advice = "建议您继续深化技术能力，同时提升团队协作和沟通能力，可以考虑往技术管理方向发展。";

        Mockito.when(aiInsightService.generateCareerAdvice(studentId, "hr001"))
            .thenReturn(advice);

        mockMvc.perform(get("/api/talent-analysis/ai-insight/student/{studentId}/career-advice", studentId)
                .param("hrUserId", "hr001"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data").value(advice));
    }

    @Test
    public void testGetCareerAdvice_serviceException() throws Exception {
        String studentId = "660e8400-e29b-41d4-a716-446655440101";

        Mockito.when(aiInsightService.generateCareerAdvice(anyString(), any()))
            .thenThrow(new RuntimeException("AI服务故障"));

        mockMvc.perform(get("/api/talent-analysis/ai-insight/student/{studentId}/career-advice", studentId))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(500))
            .andExpect(jsonPath("$.message", containsString("生成职业建议失败")));
    }

    // ==================== Helper Methods ====================

    private StudentInsight createMockInsight(String studentId) {
        StudentInsight insight = new StudentInsight();
        insight.setStudentId(studentId);
        insight.setStudentName("张三");
        insight.setMajor("软件工程");
        insight.setGeneratedTime(LocalDateTime.now());
        insight.setAiModelVersion("GPT-4");
        insight.setOverallEvaluation("综合能力优秀");
        
        insight.setStrengths(Arrays.asList("技术能力强", "学习能力优秀"));
        insight.setWeaknesses(Arrays.asList("沟通能力需提升"));
        
        List<JobRecommendation> jobs = new ArrayList<>();
        jobs.add(createMockJobRecommendation("软件开发工程师", 95.0));
        insight.setJobRecommendations(jobs);
        
        TaskCategoryAnalysis taskAnalysis = createMockTaskAnalysis();
        insight.setTaskCategoryAnalysis(taskAnalysis);
        
        return insight;
    }

    private JobRecommendation createMockJobRecommendation(String title, Double matchScore) {
        JobRecommendation job = new JobRecommendation();
        job.setJobTitle(title);
        job.setJobCategory("技术研发");
        job.setMatchScore(matchScore);
        job.setRecommendationReason("能力匹配度高");
        job.setSupportingData(Arrays.asList("技术能力4.5/5.0", "项目经验丰富"));
        job.setRequiredSkills(Arrays.asList("Java", "Spring", "MySQL"));
        job.setMatchedSkills(Arrays.asList("Java", "Spring"));
        return job;
    }

    private TaskCategoryAnalysis createMockTaskAnalysis() {
        TaskCategoryAnalysis analysis = new TaskCategoryAnalysis();
        analysis.setPerformanceTrend("进步明显");
        analysis.setAiSummary("个人任务：完成10个任务，平均分85.5，优秀率60%。");
        
        Map<String, TaskCategoryAnalysis.CategoryPerformance> perfMap = new HashMap<>();
        TaskCategoryAnalysis.CategoryPerformance perf = new TaskCategoryAnalysis.CategoryPerformance();
        perf.setCategory("个人任务");
        perf.setTaskCount(10);
        perfMap.put("个人任务", perf);
        analysis.setPerformanceByType(perfMap);
        
        analysis.setHighScoreTasks(new ArrayList<>());
        analysis.setLowScoreTasks(new ArrayList<>());
        
        return analysis;
    }
}
